/**
 * Copyright  2025, Hai Yue Xing He Technology Co., Ltd
 * 
 * @author        ZHAO LIMIN
 * @version       1.0.1
 * @since         2025-04
 * SecenesManager.ts       用于管理场景的类，及各个资源的加载
 *                         所有场景的通用资源在启动游戏的时候，
 *                         统一加载到内存中，方便后续使用
 *                         主要是加载场景资源，及场景中的资源，
 *                         如：
 *                         1. 加载场景资源，如：场景的模型，场景的贴图，场景的声音等
 */
import { _decorator, Sprite, Node, Animation, resources, director, JsonAsset, error, ImageAsset, Texture2D, SpriteFrame, AudioClip, AnimationClip } from 'cc';
import { defined } from '../hyxh/core/Defined';
import { Check } from '../hyxh/core/Check';
import { FrameFrame, HAnimationControlResource, HAnimationFrame, HAnimationResource, HAudioResource, HImageResource, HResource, HResourceType } from './HResource';
import { Rectangle } from '../hyxh/core/Rectangle';
import { Cartesian3 } from '../hyxh/core/Cartesian3';

const MAX_RESOURCES_COUNT = 200;
/* 在资源加载中，回调 */
export type ONResourcesLoading = (totalCount: number, count: number) => void;
/* 资源加载完成后，回调 */
export type ONResourcesLoaded = () => void;

export class SecenesManager {
    private static _instance: SecenesManager;
    public jsonConfig:object = null;
    /* 场景资源缓存池，用于存储场景资源，如：场景的模型，场景的贴图，场景的声音等 */
    private _mediaMap = new Map<number, HResource>();
    /* 场景信息 */
    private _secenesMap = new Map<string, Object>();

    private countOfLoadedResources: number = 0;

    public static getInstance(): SecenesManager {
        if (!SecenesManager._instance) {
            SecenesManager._instance = new SecenesManager();
        }
        return SecenesManager._instance;
    }
    /**
     * 根据json 配置文件读取JSON
     * @param confUrl JSON 配置文件
     * @param onResourcesLoading 
     * @param onResourcesLoaded 
     */
    public loadResources(confUrl:string, 
        onResourcesLoading: ONResourcesLoading, 
        onResourcesLoaded: ONResourcesLoaded) {
        this.loadjsonConfig(onResourcesLoading, onResourcesLoaded);
    }

    loadjsonConfig( loading: ONResourcesLoading, loaded: ONResourcesLoaded) {
        resources.load('config/hxpath', (err: any, res: JsonAsset) => {
            if (err) {
                error(err.message??err);
                return;
            }
            /* 读取JSON 配置 */
            let secenesManager =  SecenesManager.getInstance();
            if (!secenesManager) {
                error('SecenesManager is null');
                return; 
            }
            if (!res) {
                error('json file loaded failue, res is null!');
                return;
            }
            secenesManager.jsonConfig = res.json!;
            if (defined(loading) ){
                /* 记录加载 */
                loading(MAX_RESOURCES_COUNT, ++secenesManager.countOfLoadedResources);
            }
            const res_list_conf = secenesManager.scanJSONConfigForResources();
            if (defined(res_list_conf) && res_list_conf.length > 0) {
                secenesManager.loadGameResources(res_list_conf, loading, loaded); 
            }
            if (!defined( this._mediaMap )){
                this._mediaMap = new Map();
            }
            for (let hresource of res_list_conf) {
                if (!defined(hresource)) {
                    continue;               
                }
                this._mediaMap.set(hresource.rid, hresource);
            }
            /* 装载Secence 配置 */
            this.loadSecenesRef(secenesManager._secenesMap, secenesManager.jsonConfig );
            /* 配置 */
            if (defined(loaded) ){
                loaded();
            }
        });     
    }

    /**
     * 根据rid 获得相应资源
     * @param rid 
     * @returns 
     */
    public getResource(rid: number): HResource {
        if (!defined(this._mediaMap)) {
            return null;
        } 
        return this._mediaMap.get(rid);
    }
    public getSeceneReference(name: string): Object {
        if (!defined(this._secenesMap)) {
            return null; 
        }
        return this._secenesMap.get(name);        
    }
    /**
     * 装载场景资源
     * @param secene
     */
    loadSecenesRef(_secenesMap: Map<string, Object>, jsonConfig: Object) {
        if (!defined(jsonConfig)) {
            return; 
        }
        if (!defined(_secenesMap)) {
            return;
        }

        if(!defined(jsonConfig['secenes'])){
            return;
        }
        const secenes = jsonConfig['secenes'];
        if (!defined(secenes)) {
            return;
        }
        if(!Array.isArray(secenes)){
            return;
        }
        for (let secene of secenes) {
            if (!defined(secene)) {
                continue;
            }
            if (!defined(secene['name'])) {
                continue;
            } 
            const _key = secene['name'];
            _secenesMap.set(_key, secene);
        }
    }

    async loadImageResources(
        hresource: HResource,
        loading: ONResourcesLoading,
        loaded: ONResourcesLoaded) : Promise<void> {
        if (!defined(hresource)) {
            return;
        }
        if (hresource.model != HResourceType.IMAGE) {
            return;        
        }
        const himage = hresource as HImageResource;
        if (!defined(himage)) {
            return;
        }
        try {
            await new Promise<void>((resolve, reject) => {
                resources.load<ImageAsset>(himage.url, ImageAsset, (err: any, res: ImageAsset) =>{
                    if (err) {
                        error(err.message??err);
                        return;
                    }
                    if (defined(res) ){
                        const texture = new Texture2D();
                        texture.image = res;

                        const spriteFrame = new SpriteFrame();
                        spriteFrame.texture = texture;
                        /* 记录加载 */
                        himage.spriteFrame = spriteFrame;  
                        if (defined(loading) ){
                            /* 记录加载 */
                            loading(MAX_RESOURCES_COUNT, ++this.countOfLoadedResources);
                        }
                        resolve();        
                    }
                } );
            }).then(()=>{});
 
        }catch(lerr) {
            error(lerr.message??lerr);
        }
    }

    async loadAudioResources(
        hresource: HResource,
        loading: ONResourcesLoading,
        loaded: ONResourcesLoaded) : Promise<void> {
        if (!defined(hresource)) {
            return;
        }
        if (hresource.model != HResourceType.AUDIO) {
            return;        
        }
        const haudio = hresource as HAudioResource;
        if (!defined(haudio)) {
            return;
        }
        try {
            await new Promise<void>((resolve, reject) => {
                resources.load<AudioClip>(haudio.url, AudioClip, (err: any, res: AudioClip) =>{
                    if (err) {
                        error(err.message??err);
                        return;
                    }
                    if (defined(res) ){
                        /* 记录加载 */
                        haudio.audioClip = res;
                        if (defined(loading) ){
                            /* 记录加载 */
                            loading(MAX_RESOURCES_COUNT, ++this.countOfLoadedResources);
                        }
                        resolve(); 
                    } 
                }) 
            }).then(()=>{});
        }catch(lerr) {
            error(lerr.message??lerr);
        }
    }

    async loadAnimationResources(
        hresource: HResource,
        loading: ONResourcesLoading,
        loaded: ONResourcesLoaded) : Promise<void> {
        if (!defined(hresource)) {
            return;
        }
        if (hresource.model != HResourceType.ANIMATION) {
            return;        
        }
        const _animation = hresource as HAnimationResource;
        if (!defined(_animation)) {
            return;
        }
        try {
            await new Promise<void>((resolve, reject) => {
                resources.load<AnimationClip>(_animation.url, AnimationClip, (err: any, res: AnimationClip) =>{
                    if (err) {
                        error(err.message??err);
                        return;
                    }
                    if (defined(res) ){
                        /* 记录加载 */
                        _animation.animationClip = res;
                        if (defined(loading) ){
                            /* 记录加载 */
                            loading(MAX_RESOURCES_COUNT, ++this.countOfLoadedResources);
                        }
                        resolve();                         
                    } 
                }) 
            }).then(()=>{});
        }catch(lerr) {
            error(lerr.message??lerr);
        }
    }

    loadAnimationControlFrameResources(
        hresource: HResource,
        loading: ONResourcesLoading,
        loaded: ONResourcesLoaded) {
        if (!defined(hresource)) {
            return;
        }
        if (hresource.model != HResourceType.ANIMATIONCONTROL) {
            return;        
        }
        const _animation = hresource as HAnimationControlResource;
        if (!defined(_animation)) {
            return; 
        }
        if (defined(loading)) {
            loading(MAX_RESOURCES_COUNT, ++this.countOfLoadedResources);
        }
    }

    loadGameResources(
        hresourcelist: Array<HResource>,
        loading: ONResourcesLoading,
        loaded: ONResourcesLoaded) {
        if ( !defined(hresourcelist)) {
            return; 
        }
        if (hresourcelist.length <= 0) {
            return; 
        }
        for (let hresource of hresourcelist) {
            if (!defined(hresource)) {
                continue;
            }
            if (hresource.model == HResourceType.IMAGE) {
                this.loadImageResources(hresource, loading, loaded);
                
            } else if ( hresource.model == HResourceType.AUDIO) {
                const haudio = hresource as HAudioResource;
                if (!defined(haudio)) {
                    continue;
                }
                this.loadAudioResources(hresource, loading, loaded);      
            }else if ( hresource.model == HResourceType.ANIMATION) {
                const hanimation = hresource as HAnimationResource;
                if (!defined(hanimation)) {
                    continue;
                }
                this.loadAnimationResources(hanimation, loading, loaded);                
            }
            else if ( hresource.model == HResourceType.ANIMATIONCONTROL) {
                const hanimationControl = hresource as HAnimationControlResource;
                if (!defined(hanimationControl)) {
                    continue;
                }
                this.loadAnimationControlFrameResources(hanimationControl, loading, loaded);                
            }
        }
    }

    public scanJSONConfigForResources(): Array<HResource> {
        Check.defined('this.jsonConfig', this.jsonConfig);
        let _game_resources: Array<HResource> = [];

        if (!defined(this.jsonConfig)) {
            return _game_resources;
        }

        const json_resources = this.jsonConfig['resources'];
        if (!defined(json_resources)) {
            return _game_resources;
        }

        for (let res of json_resources) {
            if (!defined(res)) {
                continue;
            }
            const rid = res['RID']??res['rid'];
            const model = res['model'];
            const name = res['name'];
            const url = res['url'];
            const frames = res['frames'];
            let hresource: HResource = null;
            if (model == 1) {
                hresource = new HImageResource(rid, name, url);                
            } else if (model == 2) {
                hresource = new HAudioResource(rid, name, url);
            } else if (model == 3) {
                hresource = new HAudioResource(rid, name, url);
            } else if (model == 4) {
                hresource = new HAnimationResource(rid, name, url);
            } else if (model == 5) {
                hresource = new HAnimationControlResource(rid, name, url);

                /* 进行加载 */
                (hresource as HAnimationControlResource).speed = res['speed']?? 1.0;
                (hresource as HAnimationControlResource).sample = res['sample']?? 10.0;
                (hresource as HAnimationControlResource).duration = res['duration']?? 1.0;
                (hresource as HAnimationControlResource).animframes = [];

                const anFrames =  res['animframes'];
                if (defined(anFrames) &&
                    Array.isArray(anFrames) &&
                    anFrames.length > 0) {
                    for (let anFrame of anFrames) {
                        if (!defined(anFrame)) {
                            continue;
                        }                         
                        const _hframe = new HAnimationFrame();
                        _hframe.index = anFrame['index'];
                        _hframe.frame = anFrame['frame'];
                        _hframe.translation = anFrame['translation'];
                        _hframe.rotation = anFrame['rotation'];
                        _hframe.scale = anFrame['scale'];
                        (hresource as HAnimationControlResource).animframes.push(_hframe);
                    }
                }

            }            
            if(!defined(frames)) {
                _game_resources.push(hresource);
                continue;
            }
            hresource.frames = new FrameFrame();
            hresource.frames.rect = new Rectangle(frames['x'], frames['y'], frames['width'], frames['height']);
            hresource.frames.sourceSize = frames['spriteSourceSize'];
            hresource.frames.size = frames['spriteSize'];
           
            _game_resources.push(hresource);
        }
        return _game_resources;
    }

    /**
     * 动态播放
     * @param _node 
     * @param _sprite 
     * @param rid 
     * @returns 
     */
    public static playAnimation(
        _node: Node,
        _sprite: Sprite, 
        rid: number, 
        onAnimationEventFromFram: (frameIndex: number) => void = onAnimationEventFromFramPlay   
    ) {
        if(!defined(_node)) {
            return;
        }
        if (animation_playing) {
            return;
        }

        const animation_result = SecenesManager.getInstance().getResource(rid) as HAnimationControlResource;
        if (!defined(animation_result)){
            return;
        }
        
        let spriteFrames = [];
        /* 获得Sprite Frame 数组 */
        if (!defined(animation_result.animframes)){
            return;
        }
        if (animation_result.animframes.length <= 0) {
            return;
        }
        if (!defined(animation_resources)) {
            return;
        }
        /* 记录 */
        animation_sprite = _sprite;
        animation_resources = [];
        animation_node = _node;

        for(let anframe of animation_result.animframes) {
            if(!defined(anframe)){
                continue;
            }
            const frame_rid = anframe.frame;
            const framResource = SecenesManager.getInstance().getResource(frame_rid) as HImageResource;
            if(!defined(framResource)) {
                continue;
            }
            if(!defined(framResource.spriteFrame)) {
                continue;
            }
            animation_resources.push(anframe);
            spriteFrames.push(framResource.spriteFrame);
        }
        
        const animation = _node.addComponent(Animation);
        if(!defined(animation)) {
            return;
        }
        const clip = AnimationClip.createWithSpriteFrames(spriteFrames, spriteFrames.length);
        if(!defined(clip)) {
            return;
        }
        /* 设置事件，用于根据配置，进行处理 */
        let k = 1;
        for(let anframe of animation_result.animframes) {
            if (!defined(anframe)) {
                continue;
            }
            clip.events.push({
                frame: clip.duration / clip.sample * k,
                func: 'onAnimationEventFromFramPlay',
                params:[k.toString()]
            });
            k++;
        }

        clip.name = animation_result.name;
        animation.addClip(clip);
        animation.defaultClip = clip;
        animation.play();
        animation_playing = true;

        animation.on(Animation.EventType.FINISHED, () => {
            /* 播放完成 */
            if (defined(animation)) { 
                animation.enabled = false;
            }
            if (defined(animation_resources)) {
                animation_resources.length = 0;
            }
            if (defined(animation_sprite)) {
                animation_sprite = null;
            }
            if (defined(animation_node)) {
                animation_node = null;
            }
            if (defined(animation)) {
                animation.destroy(); 
            }
            animation_playing = false;
        });
    }   
    public static showImage(_node: Node, imageResource: HImageResource) {
        if (!defined(_node)) {
            return;
        }

        if (!defined(imageResource)) {
            return;
        }

        let sprite = _node.getComponent(Sprite);
        if(!defined(sprite)) {
            sprite = _node.addComponent(Sprite);
        }
        sprite.spriteFrame = imageResource.spriteFrame; 
        if (defined(imageResource.frames)) {
            const x_scale = imageResource.frames.size[0]/imageResource.frames.sourceSize[0];
            const y_scale = imageResource.frames.size[1]/imageResource.frames.sourceSize[1];
            _node.setScale( x_scale, y_scale, 0.0 );
        }
        if (!sprite.enabled ){
            sprite.enabled = true;
        }
    }

    public static hideImage(_node: Node) { 
        if (!defined(_node)) {
            return;
        }
        let sprite = _node.getComponent(Sprite);
        if(!defined(sprite)) {
            return;
        }
        sprite.enabled = false;
    }

    public static unhideImage(_node: Node) { 
        if (!defined(_node)) {
            return;
        }
        let sprite = _node.getComponent(Sprite);
        if(!defined(sprite)) {
            return;
        }
        sprite.enabled = true;
    }

}
let animation_node : Node = null;
let animation_sprite: Sprite = null;
let animation_resources : Array<HAnimationFrame> = [];
let animation_playing = false;

function onAnimationEventFromFramPlay(index: number ) {
    console.log("px:" + index);
    if ( index < 0) {
        return;
    }
    if ( !defined(animation_resources)) {
        return;
    }
    if (animation_resources.length <= 0 ) {
        return;
    }
    if (!defined(animation_sprite)) {
        return;
    }
    if (!defined(animation_node)) {
        return;
    }

    const animation_frame = animation_resources[index];
    if( !defined(animation_frame)) {
        return;
    }

    if (!defined(animation_frame.frame)) {
        return;
    }

    const image_sprite_frame_result = SecenesManager.getInstance().getResource(animation_frame.frame) as HImageResource ;
    if (!defined(image_sprite_frame_result)) {
        return;
    }

    animation_sprite.spriteFrame = image_sprite_frame_result.spriteFrame;

    if(defined(animation_frame.rotation)){
        /* 进行移动 */
        let _org_car = new Cartesian3(animation_node.getPosition().x, animation_node.getPosition().y, animation_node.getPosition().z );
        let _rotation = new Cartesian3(animation_frame.rotation[0], animation_frame.rotation[1], animation_frame.rotation[2]);
        _org_car = Cartesian3.multiplyComponents(_org_car, _rotation) as Cartesian3;

        if(defined(_org_car)) {
            animation_node.setPosition( _org_car.x, _org_car.y, _org_car.y );
        }
    }

    if(defined(animation_frame.translation)){
        /* 进行移动 */
        let _org_car = new Cartesian3(animation_node.getPosition().x, animation_node.getPosition().y, animation_node.getPosition().z );
        let _translation = new Cartesian3(animation_frame.rotation[0], animation_frame.rotation[1], animation_frame.rotation[2]);
        _org_car = Cartesian3.add(_org_car, _translation) as Cartesian3;

        if(defined(_org_car)) {
            animation_node.setPosition( _org_car.x, _org_car.y, _org_car.y );
        }
    }

    if(defined(animation_frame.scale)){
        /* 按照比例进行缩放 */
        let scale_mix = new Cartesian3(1.0, 1.0, 1.0);
        if (defined(image_sprite_frame_result.frames)) {
            scale_mix.x =  image_sprite_frame_result.frames.size[0]/image_sprite_frame_result.frames.sourceSize[0];
            scale_mix.y = image_sprite_frame_result.frames.size[1]/image_sprite_frame_result.frames.sourceSize[1];
        }

        let base_scale_car = new Cartesian3(animation_frame.scale[0], animation_frame.scale[1], animation_frame.scale[2]);

        scale_mix = Cartesian3.multiplyComponents(scale_mix, base_scale_car) as Cartesian3;
        if (defined(scale_mix)) {
            animation_node.setScale(scale_mix.x, scale_mix.y, scale_mix.z);
        } else {
            animation_node.setScale(animation_frame.scale[0], animation_frame.scale[1], animation_frame.scale[2]);
        }
    }
}

